package cn.lb.framework.poi.pdf.export;

import cn.lb.framework.poi.cache.ImageCache;
import cn.lb.framework.poi.excel.annotation.ExcelTarget;
import cn.lb.framework.poi.excel.entity.params.ExcelExportEntity;
import cn.lb.framework.poi.excel.export.base.ExportBase;
import cn.lb.framework.poi.pdf.entity.PdfCellParams;
import cn.lb.framework.poi.pdf.entity.PdfExportParams;
import cn.lb.framework.poi.pdf.entity.PdfTableParams;
import cn.lb.framework.poi.pdf.entity.PdfTemplateExportParams;
import cn.lb.framework.poi.pdf.styler.IPdfExportStyler;
import cn.lb.framework.poi.pdf.styler.PdfExportStylerDefaultImpl;
import cn.lb.framework.poi.util.PoiPublicUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.util.*;
import java.util.List;

/**
 * PDF导出服务,基于Excel基础的导出
 */
public class PdfExportServer extends ExportBase {

    private static final Logger LOGGER = LoggerFactory.getLogger(PdfExportServer.class);

    private static Font headfont;// 设置字体大小
    private static Font keyfont;// 设置字体大小
    private static Font textfont;// 设置字体大小

    static {
        BaseFont bfChinese;
        try {
            bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            headfont = new Font(bfChinese, 10, Font.BOLD);// 设置字体大小
            keyfont = new Font(bfChinese, 8, Font.BOLD);// 设置字体大小
            textfont = new Font(bfChinese, 8, Font.NORMAL);// 设置字体大小
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Document document;
    private IPdfExportStyler styler;
    private int maxWidth = 520;

    private boolean isListData = false;

    public PdfExportServer(OutputStream outStream, PdfExportParams entity) {
        try {
            styler = entity.getStyler() == null ? new PdfExportStylerDefaultImpl() : entity.getStyler();
            document = styler.getDocument();
            PdfWriter.getInstance(document, outStream);
            document.open();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    public PdfExportServer(OutputStream outStream) {
        try {
            document = new Document(PageSize.A4);
            PdfWriter.getInstance(document, outStream);
            document.open();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    public PdfExportServer() {
    }

    /**
     * 创建Pdf的表格数据
     *
     * @param entity
     * @param pojoClass
     * @param dataSet
     * @return
     */
    public Document createPdf(PdfExportParams entity, Class<?> pojoClass, Collection<?> dataSet) {
        try {
            List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
            if (entity.isAddIndex()) {
                //excelParams.add(indexExcelEntity(entity));
            }
            // 得到所有字段
            Field fileds[] = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
            String targetId = etarget == null ? null : etarget.value();
            getAllExcelField(entity.getExclusions(), targetId, fileds, excelParams, pojoClass, null);
            createPdfByExportEntity(entity, excelParams, dataSet);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            try {
                document.close();
            } catch (Exception e) {
                //可能之前已经关闭过了
            }
        }
        return document;
    }

    public Document createPdfByExportEntity(PdfExportParams entity, List<ExcelExportEntity> excelParams, Collection<?> dataSet) {
        try {
            sortAllParams(excelParams);
            for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) {
                if (excelParams.get(k).getList() != null) {
                    isListData = true;
                    break;
                }
            }
            //设置各个列的宽度
            float[] widths = getCellWidths(excelParams);
            PdfPTable table = new PdfPTable(widths.length);
            table.setTotalWidth(widths);
            //table.setLockedWidth(true);
            //设置表头
            createHeaderAndTitle(entity, table, excelParams);
            int rowHeight = getRowHeight(excelParams) / 50;
            Iterator<?> its = dataSet.iterator();
            while (its.hasNext()) {
                Object t = its.next();
                createCells(table, t, excelParams, rowHeight);
            }
            document.add(table);
        } catch (DocumentException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            document.close();
        }
        return document;
    }

    private void createCells(PdfPTable table, Object t, List<ExcelExportEntity> excelParams,
                             int rowHeight) throws Exception {
        ExcelExportEntity entity;
        int maxHeight = getThisMaxHeight(t, excelParams);
        for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) {
            entity = excelParams.get(k);
            if (entity.getList() != null) {
                Collection<?> list = getListCellValue(entity, t);
                for (Object obj : list) {
                    createListCells(table, obj, entity.getList(), rowHeight);
                }
            } else {
                Object value = getCellValue(entity, t);
                if (entity.getType() == 1) {
                    createStringCell(table, value == null ? "" : value.toString(), entity,
                            rowHeight, 1, maxHeight);
                } else {
                    createImageCell(table, value == null ? "" : value.toString(), entity, rowHeight,
                            1, maxHeight);
                }
            }
        }
    }

    /**
     * 创建集合对象
     *
     * @param table
     * @param obj
     * @param rowHeight
     * @param excelParams
     * @throws Exception
     */
    private void createListCells(PdfPTable table, Object obj, List<ExcelExportEntity> excelParams,
                                 int rowHeight) throws Exception {
        ExcelExportEntity entity;
        for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) {
            entity = excelParams.get(k);
            Object value = getCellValue(entity, obj);
            if (entity.getType() == 1) {
                createStringCell(table, value == null ? "" : value.toString(), entity, rowHeight);
            } else {
                createImageCell(table, value == null ? "" : value.toString(), entity, rowHeight, 1,
                        1);
            }
        }
    }

    /**
     * 获取这一列的高度
     *
     * @param t           对象
     * @param excelParams 属性列表
     * @return
     * @throws Exception 通过反射过去值得异常
     */
    private int getThisMaxHeight(Object t, List<ExcelExportEntity> excelParams) throws Exception {
        if (isListData) {
            ExcelExportEntity entity;
            int maxHeight = 1;
            for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) {
                entity = excelParams.get(k);
                if (entity.getList() != null) {
                    Collection<?> list = getListCellValue(entity, t);
                    maxHeight = (list == null || maxHeight > list.size()) ? maxHeight : list.size();
                }
            }
            return maxHeight;
        }
        return 1;
    }

    /**
     * 获取Cells的宽度数组
     *
     * @param excelParams
     * @return
     */
    private float[] getCellWidths(List<ExcelExportEntity> excelParams) {
        List<Float> widths = new ArrayList<Float>();
        for (int i = 0; i < excelParams.size(); i++) {
            if (excelParams.get(i).getList() != null) {
                List<ExcelExportEntity> list = excelParams.get(i).getList();
                for (int j = 0; j < list.size(); j++) {
                    widths.add((float) (20 * list.get(j).getWidth()));
                }
            } else {
                widths.add((float) (20 * excelParams.get(i).getWidth()));
            }
        }
        float[] widthArr = new float[widths.size()];
        for (int i = 0; i < widthArr.length; i++) {
            widthArr[i] = widths.get(i);
        }
        return widthArr;
    }

    private void createHeaderAndTitle(PdfExportParams entity, PdfPTable table,
                                      List<ExcelExportEntity> excelParams) throws DocumentException {
        int feildWidth = getFieldLength(excelParams);
        if (entity.getTitle() != null) {
            createHeaderRow(entity, table, feildWidth);
        }
        createTitleRow(entity, table, excelParams);
    }

    /**
     * 创建表头
     *
     * @param title
     * @param table
     */
    private int createTitleRow(PdfExportParams title, PdfPTable table,
                               List<ExcelExportEntity> excelParams) {
        int rows = getRowNums(excelParams);
        for (int i = 0, exportFieldTitleSize = excelParams.size(); i < exportFieldTitleSize; i++) {
            ExcelExportEntity entity = excelParams.get(i);
            if (entity.getList() != null) {
                if (StringUtils.isNotBlank(entity.getName())) {
                    createStringCell(table, entity.getName(), entity, 10, entity.getList().size(),
                            1);
                }
                List<ExcelExportEntity> sTitel = entity.getList();
                for (int j = 0, size = sTitel.size(); j < size; j++) {
                    createStringCell(table, sTitel.get(j).getName(), sTitel.get(j), 10);
                }
            } else {
                createStringCell(table, entity.getName(), entity, 10, 1, rows == 2 ? 2 : 1);
            }
        }
        return rows;

    }

    private void createHeaderRow(PdfExportParams entity, PdfPTable table, int feildLength) {
        PdfPCell iCell = new PdfPCell(
                new Phrase(entity.getTitle(), styler.getFont(null, entity.getTitle())));
        iCell.setHorizontalAlignment(Element.ALIGN_CENTER);
        iCell.setVerticalAlignment(Element.ALIGN_CENTER);
        iCell.setFixedHeight(entity.getTitleHeight());
        iCell.setColspan(feildLength + 1);
        table.addCell(iCell);
        if (entity.getSecondTitle() != null) {
            iCell = new PdfPCell(
                    new Phrase(entity.getSecondTitle(), styler.getFont(null, entity.getSecondTitle())));
            iCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            iCell.setVerticalAlignment(Element.ALIGN_CENTER);
            iCell.setFixedHeight(entity.getSecondTitleHeight());
            iCell.setColspan(feildLength + 1);
            table.addCell(iCell);
        }
    }

    private PdfPCell createStringCell(PdfPTable table, String text, ExcelExportEntity entity,
                                      int rowHeight, int colspan, int rowspan) {
        PdfPCell iCell = new PdfPCell(new Phrase(text, styler.getFont(entity, text)));
        styler.setCellStyler(iCell, entity, text);
        iCell.setFixedHeight((int) (rowHeight * 2.5));
        if (colspan > 1) {
            iCell.setColspan(colspan);
        }
        if (rowspan > 1) {
            iCell.setRowspan(rowspan);
        }
        table.addCell(iCell);
        return iCell;
    }

    private PdfPCell createStringCell(PdfPTable table, String text, ExcelExportEntity entity,
                                      int rowHeight) {
        PdfPCell iCell = new PdfPCell(new Phrase(text, styler.getFont(entity, text)));
        styler.setCellStyler(iCell, entity, text);
        iCell.setFixedHeight((int) (rowHeight * 2.5));
        table.addCell(iCell);
        return iCell;
    }

    private PdfPCell createImageCell(PdfPTable table, String text, ExcelExportEntity entity,
                                     int rowHeight, int rowSpan, int colSpan) {
        try {
            Image image = Image.getInstance(ImageCache.getImage(text));
            PdfPCell iCell = new PdfPCell(image);
            styler.setCellStyler(iCell, entity, text);
            iCell.setFixedHeight((int) (rowHeight * 2.5));
            table.addCell(iCell);
            return iCell;
        } catch (BadElementException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (MalformedURLException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }
        return new PdfPCell();

    }

    /**
     * 创建Pdf的表格数据
     *
     * @param entity
     * @param dataSet
     * @return
     */
    public Document createPdf(PdfTemplateExportParams entity, Map<String, Object> dataSet, OutputStream out) {
        PdfReader reader = null;
        ByteArrayOutputStream bos = null;
        PdfStamper stamper;
        Document doc = null;
        PdfCopy copy = null;
        try {
            String templatePath = entity.getTemplateUrl();
            reader = new PdfReader(templatePath);//读取pdf模板
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);
            AcroFields form = stamper.getAcroFields();
            int pageNum = reader.getNumberOfPages();

            FontFactory.registerDirectories();
            //用以支持中文
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
                    BaseFont.NOT_EMBEDDED);

            java.util.Iterator<String> it = form.getFields().keySet().iterator();
            String name = null;
            String value = null;

            while (it.hasNext()) {
                name = it.next().toString();
                form.setFieldProperty(name, "textfont", bfChinese, null);
                if (dataSet.containsKey(name)) {
                    value = String.valueOf(dataSet.get(name));
                } else {
                    continue;
                }
                form.setField(name, value);
            }
            stamper.setFormFlattening(entity.isCanModify() == null ? false : entity.isCanModify());//如果为false那么生成的PDF文件还能编辑
            stamper.close();

            doc = new Document(PageSize.A4);
            copy = new PdfCopy(doc, out);
            doc.open();
            for (int i = 0; i < pageNum; i++) {
                PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i + 1);
                copy.addPage(importPage);
            }
        } catch (DocumentException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            if (copy != null) {
                copy.close();
            }
            if (doc != null) {
                doc.close();
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (reader != null) {
                reader.close();
            }
        }
        return doc;
    }


    public Document generatePdf(PdfTableParams params) {

        try {
            PdfPTable table = createTable(params.getColumns());
            //标题
            if (params.getTitleCell() != null) {
                table.addCell(createCell(params.getTitleCell().getValue(),
                        params.getTitleCell().getFont() == null ? headfont : params.getTitleCell().getFont(),
                        params.getTitleCell().getColAlign() == null ? Element.ALIGN_CENTER : params.getTitleCell().getColAlign(),
                        params.getTitleCell().getColSpan() == null ? params.getColumns() : params.getTitleCell().getColSpan(),
                        params.getTitleCell().isBoderFlag() == null ? false : params.getTitleCell().isBoderFlag()));
            }
            //表头
            List<PdfCellParams> headerCellParams = params.getHeaderList();
            for (PdfCellParams cellParam : headerCellParams) {
                table.addCell(createCell(cellParam.getValue(), cellParam.getFont() == null ? keyfont : cellParam.getFont(),
                        cellParam.getColAlign() == null ? Element.ALIGN_CENTER : cellParam.getColAlign(),
                        cellParam.getColSpan() == null ? 1 : cellParam.getColSpan(),
                        cellParam.isBoderFlag() == null ? true : cellParam.isBoderFlag()));
            }
            //正文
            List<PdfCellParams> cellParams = params.getCellList();
            for (PdfCellParams cellParam : cellParams) {
                PdfPCell cell = createCell(cellParam.getValue(), cellParam.getFont() == null ? textfont : cellParam.getFont(),
                        cellParam.getColAlign() == null ? Element.ALIGN_CENTER : cellParam.getColAlign(),
                        cellParam.getColSpan() == null ? 1 : cellParam.getColSpan(),
                        cellParam.isBoderFlag() == null ? true : cellParam.isBoderFlag());
                if (cellParam.getPaddingRight() != null && cellParam.getPaddingRight() > 0f) {
                    cell.setPaddingRight(cellParam.getPaddingRight());
                }
                if (cellParam.getPaddingLeft() != null && cellParam.getPaddingLeft() > 0f) {
                    cell.setPaddingLeft(cellParam.getPaddingLeft());
                }
                table.addCell(cell);
            }

            document.add(table);
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return document;
    }

    /**
     * 根据列数创建表格
     *
     * @param colNumber 列数
     * @return
     */
    public PdfPTable createTable(int colNumber) {
        PdfPTable table = new PdfPTable(colNumber);
        try {
            table.setTotalWidth(maxWidth);
            table.setLockedWidth(true);
            table.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.getDefaultCell().setBorder(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return table;
    }

    /**
     * 根据宽度创建表格
     *
     * @param widths 绝对宽度
     * @return
     */
    public PdfPTable createTable(float[] widths) {
        PdfPTable table = new PdfPTable(widths);
        try {
            table.setTotalWidth(maxWidth);
            table.setLockedWidth(true);
            table.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.getDefaultCell().setBorder(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return table;
    }

    /**
     * 创建空表格
     *
     * @return
     */
    public PdfPTable createBlankTable() {
        PdfPTable table = new PdfPTable(1);
        table.getDefaultCell().setBorder(0);
        table.addCell(createCell("", keyfont));
        table.setSpacingAfter(20.0f);
        table.setSpacingBefore(20.0f);
        return table;
    }

    /**
     * 创建单元格
     *
     * @param value
     * @param font
     * @param align
     * @return
     */
    public PdfPCell createCell(String value, Font font, int align) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(align);
        cell.setPhrase(new Phrase(value, font));
        return cell;
    }

    /**
     * 创建单元格
     *
     * @param value
     * @param font
     * @return
     */
    public PdfPCell createCell(String value, Font font) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setPhrase(new Phrase(value, font));
        return cell;
    }

    /**
     * 创建单元格
     *
     * @param value
     * @param font
     * @param align
     * @param colspan
     * @return
     */
    public PdfPCell createCell(String value, Font font, int align, int colspan) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(align);
        cell.setColspan(colspan);
        cell.setPhrase(new Phrase(value, font));
        return cell;
    }
    
    /**
     * 创建单元格
     *
     * @param value
     * @param font
     * @param align
     * @param colspan
     * @return
     */
    public static PdfPCell createCell(String content, int align,
    	    Font FontDefault, int colspan) {
    	Phrase objPhase = new Phrase(content, FontDefault);
    	PdfPCell objCell = new PdfPCell(objPhase);
    	objCell.setPaddingLeft(50);
    	objCell.setHorizontalAlignment(align);
    	objCell.setVerticalAlignment(align);
    	objCell.setColspan(colspan);
    	objCell.setBorderWidthBottom(0);
    	objCell.setBorderWidthTop(0);
    	objCell.setBorderWidthLeft(0);
    	objCell.setBorderWidthRight(0);
    	return objCell;
    }

    /**
     * 创建单元格
     *
     * @param value
     * @param font
     * @param align
     * @param colspan
     * @param boderFlag
     * @return
     */
    public PdfPCell createCell(String value, Font font, int align, int colspan, boolean boderFlag) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(align);
        cell.setColspan(colspan);
        cell.setPhrase(new Phrase(value, font));
        cell.setPadding(3.0f);
        if (!boderFlag) {
            cell.setBorder(0);
            //cell.setPaddingTop(15.0f);
            //cell.setPaddingBottom(8.0f);
        }
        return cell;
    }
    
    public  static PdfPCell createCell(BaseFont bfChinese,String content,int[] fontType,float[] paddingType,
			float[] borderType,int[] alignType,int colspan) {
 	
 	Font FontStyleDe=null;
 	if(fontType[0]<=0f)
 	{
 		if(fontType[1]==-1f)
 		{
 			FontStyleDe = new Font(bfChinese, 9f, Font.BOLD);
 		}
 		else
 		{
 			FontStyleDe = new Font(bfChinese, 9f, fontType[1]);
 		}
 		
 	}
 	else
 	{
 		if(fontType[1]==-1f)
 		{
 			FontStyleDe = new Font(bfChinese, fontType[0], Font.BOLD);
 		}
 		else
 		{
 			FontStyleDe = new Font(bfChinese, fontType[0], fontType[1]);
 		}
 	} 
 	
	Phrase objPhase = new Phrase(content, FontStyleDe);
	PdfPCell objCell = new PdfPCell(objPhase);
	
	
	if(paddingType[0]!=-1)
	{
		objCell.setPaddingTop(paddingType[0]);
	}
	if(paddingType[1]!=-1)
	{
		objCell.setPaddingBottom(paddingType[1]);
	}
	
	if(paddingType[2]!=-1)
	{
		objCell.setPaddingLeft(paddingType[2]);
	}
	if(paddingType[3]!=-1)
	{
		objCell.setPaddingRight(paddingType[3]);
	}
	
	objCell.setBorderWidthTop(borderType[0]);
	objCell.setBorderWidthBottom(borderType[1]);
	objCell.setBorderWidthLeft(borderType[2]);
	objCell.setBorderWidthRight(borderType[3]);
	
	if(alignType[0]!=-1)
	{
		objCell.setHorizontalAlignment(alignType[0]);
	}
	if(alignType[1]!=-1)
	{
		objCell.setVerticalAlignment(alignType[1]);
	}
	
	if(colspan!=-1)
	{
		objCell.setColspan(colspan);
	}
	
	return objCell;
}
}
